#include "StdAfx.h"
#include "Utilities.h"
#include "ThresholdingIterator.h"
#include "SubpixelInfoProvider.h"
#include <cmath>

void MakeSimpleGradient(const IBitmapPicture& inPicture, Array& outResult)
{
	int w = inPicture.GetRawWidth();
	int h = inPicture.GetRawHeight();
	if (w < 2 || h < 2) return;

	const BYTE* p = inPicture.GetData();
	int offsetX = inPicture.GetOffsetX();
	int offsetY = inPicture.GetOffsetY();
	int skip = offsetY - (w-1) * offsetX;

	outResult.resize(w * h);
	float* q = &outResult[0];

	float rLeft = p[2], gLeft = p[1], bLeft = p[0];
	for (int y = 0; y < h-1; ++y)
	{
		for (int x = 1; x < w; ++x)
		{
			int s = 0;
			for (int i = 3 + 1; --i; ++p)
			{
				int dx = (int)p[offsetX] - p[0];
				int dy = (int)p[offsetY] - p[0];
				s += dx * dx + dy * dy;
			}
			*q++ = float(s);
		}
		++q; 
		p += skip;
	}
}

void MakeGradient(const IBitmapPicture& inPicture, Array& outResult)
{
	int w = inPicture.GetRawWidth();
	int h = inPicture.GetRawHeight();
	if (w < 2 || h < 2)
		return;

	const BYTE* p = inPicture.GetData();
	int offsetX = inPicture.GetOffsetX();
	int offsetY = inPicture.GetOffsetY();
	int skip = offsetY - (w-1) * offsetX;

	outResult.resize(w * h);
	float* q = &outResult[0];

	float rLeft = p[2], gLeft = p[1], bLeft = p[0];
	for (int y = 0; y < h-1; ++y)
	{
		for (int x = 1; x < w; ++x)
		{
			unsigned int s = 0;
			for (int i = 3 + 1; --i; ++p)
			{
				int d1(p[offsetX + offsetY]); 
				if (d1 < 0)
				{
					d1 = -d1;
				}

				d1 -= p[0];
				int d2(p[offsetY]); 
				if (d2 < 0)
				{
					d2 = -d2;
				}

				d2 -= p[offsetX];
				s += d1 * d1 + d2 * d2;
				if (s > 0x100000)
				{
					s = 0;
				}
			}
			*q++ = float(s);
		}
		++q; 
		p += skip;
	}
}

void MakeC2Gradient(const IBitmapPicture& inPicture, float inRadius, Array& outResult)
{
	int w = 2 * inPicture.GetRawWidth();
	int h = 2 * inPicture.GetRawHeight();
	if (w < 2 || h < 2) return;
	
	SubpixelInfoProvider data(inPicture, inRadius);
	outResult.resize(w * h);
	float* q = &outResult[0];
	for (int y = 0; y < h; ++y) for (int x = 0; x < w; ++x)
	{
		if (const SubpixelInfo* info = data.GetInfo(x, y))
		{
			*q++ = ::sqrt(::sqrt(info->a * info->a + info->b * info->b));
		}
		else
		{
			*q++ = 0;
		}
	}
}

void MakeGradientCross(const IBitmapPicture& inPicture, Array& outResult)
{
	int w = inPicture.GetRawWidth();
	int h = inPicture.GetRawHeight();
	if (w < 2 || h < 2)
		return;

	int offsetX = inPicture.GetOffsetX();
	int offsetY = inPicture.GetOffsetY();
	int skip = offsetY - (w-2) * offsetX;

	outResult.resize(w * h);
	float* q = &outResult[w+1];
	const BYTE* p = inPicture.GetData() + offsetY + offsetX;

	for (int y = 1; y < h-1; ++y)
	{
		for (int x = 1; x < w-1; ++x)
		{
			int s = 0;
			for (int i = 3 + 1; --i; ++p)
			{
				int dx = (int)p[offsetX] - p[-offsetX];
				int dy = (int)p[offsetY] - p[-offsetY];
				s += dx * dx + dy * dy;
			}
			*q++ = float(s);
		}
		q += 2; 
		p += skip;
	}
}

void MakeSensitivity(const IBitmapPicture& inPicture,float inRadius, 
	float inThresholdRelative, float inNoiseLevel, float inClutterSuppression,
	Array& outResult)
{
	ThresholdingIterator ti(inPicture, inRadius, inThresholdRelative, 
		inNoiseLevel, inClutterSuppression);
	int w = inPicture.GetRawWidth();
	int h = inPicture.GetRawHeight();
	
	outResult.resize(w * h);
	for (int y = 0; y < h; ++y) for (int x=0; x < w; ++x)
	{
		outResult[x + w * y] = ti.Intensity(x, y);
	}
}

void MakeThreshold(const IBitmapPicture& inPicture, float inRadius, 
	float inThresholdRelative, float inNoiseLevel, float inClutterSuppression,
	Array& outResult)
{
	ThresholdingIterator ti(inPicture, inRadius, inThresholdRelative, 
		inNoiseLevel, inClutterSuppression);
	int w = inPicture.GetRawWidth();
	int h = inPicture.GetRawHeight();
	
	outResult.resize(w * h);
	for (int y = 0; y < h; ++y) for (int x=0; x < w; ++x)
	{
		outResult[x + w * y] = ti.Threshold(x, y);
	}
}

void MakeC2GradientX(const IBitmapPicture& inPicture, float inRadius, 
	int inLowBits, Array& outResult)
{
	int lowX = inLowBits & 1 ? 1 : 0;
	int lowY = inLowBits & 2 ? 1 : 0;
		
	int w = inPicture.GetRawWidth();
	int h = inPicture.GetRawHeight();
	if (w < 2 || h < 2) return;

	SubpixelInfoProvider data(inPicture, inRadius);

	outResult.resize(w * h);
	float* q = &outResult[0];
	for (int y = 0; y < h; ++y) for (int x = 0; x < w; ++x)
	{
		const SubpixelInfo* info = data.GetInfo(2 * x + lowX, 2 * y + lowY);
		if (NULL != info)
		{
			*q++ = ::sqrt(::sqrt(info->a * info->a + info->b * info->b));
		}
		else
		{
			*q++ = 0;
		}
	}
}
